#ifndef THERMAL_CALC_MODEL_H
#define THERMAL_CALC_MODEL_H

#include BS_FORCE_PLUGIN_IMPORT ()
#include "calc_model.h"
#include "well_results_storage.h"
#include "fip_results_storage.h"
#include BS_STOP_PLUGIN_IMPORT ()

#include "thermal_data.h"
#include "thermal_calc_model_data.h"
#include "boundary_building.h"


namespace blue_sky{

	template <typename strategy_t>
	class thermal_calc_model;

	template <typename strategy_t>
	struct BS_API_PLUGIN thermal_calc_model_data_tmp_holder
	{
		typedef typename strategy_t::item_t         item_t;         //!< item type (floating point)
		typedef typename strategy_t::item_array_t   item_array_t;   //!< type for array of item_t values
		//! type for array of main_var_type values
		typedef typename strategy_t::template vec <main_var_type>::type main_var_array_t;
		typedef thermal_calc_model <strategy_t>     calc_model_t;   //!< calc_model type
		typedef smart_ptr <calc_model_t, true>      sp_calc_model_t;//!< smart_ptr to calc_model type

	public:

		/**
		* \brief  stores data from calc_model in holder
		* \param  calc_model pointer to calc_model instance
		* */
		void save (const sp_calc_model_t &calc_model);

		/**
		* \brief  restores data from holder to calc_model
		* \param  calc_model pointer to calc_model instance
		* */
		void restore (sp_calc_model_t &calc_model);

	public:
		item_array_t              temperature;       //!< pressure array
	};

	template <class strategy_t>
	class BS_API_PLUGIN thermal_calc_model : public calc_model<strategy_t>
	{
	public:

		typedef calc_model<strategy_t>								base_t;	//!< type for base class
		typedef thermal_calc_model<strategy_t>						this_t;

		typedef idata												idata_t;                  //!< idata type
		typedef smart_ptr<idata_t, true>							sp_idata_t;               //!< smart_ptr to idata type

		typedef thermal_calc_model_data <strategy_t>				data_t;                   //!< calc_model data, each instance for one mesh cell
		typedef typename strategy_t::template vec <data_t>::type	data_array_t;      //!< array of calc_model_data values, each value for one mesh cell

		typedef rs_mesh_iface <strategy_t>							mesh_iface_t;             //!< rs_mesh_iface type
		typedef smart_ptr <mesh_iface_t, true>						sp_mesh_iface_t;          //!< smart_ptr to rs_mesh_iface

		typedef typename strategy_t::item_array_t					item_array_t;	//!< type for array of item_t values
		typedef smart_ptr<build_boundary<strategy_t>, true>			sp_boundary_builder;

		typedef typename strategy_t::csr_matrix_t					csr_matrix_t;
		typedef typename csr_matrix_t::i_vector_type				i_vector_type;
		
		//! temporary holder for thermal_calc_model data
		typedef thermal_calc_model_data_tmp_holder<strategy_t>		thermal_calc_model_data_tmp_holder_t; 

		/**
		* \brief return number of second variables
		* \param n_phases number of phases
		* \return number of second variables
		**/
		int get_n_sec_vars(int n_phases);

		/**
		* \brief  inits main arrays
		* \param  input_data pointer to idata instance
		* \param  mesh pointer to mesh instance
		* \return 0 on success otherwise negative integer value
		* \todo   remove return values, throw exceptions instead
		* */
		int init_main_arrays (const sp_idata_t &input_data, const sp_mesh_iface_t &mesh);

		/**
		* \brief  inits initial conditions
		* \param  input_data pointer to idata instance
		* \param  mesh pointer to mesh instance
		* \return 0 on success otherwise negative integer value
		* \todo   remove return values, throw exceptions instead
		* */
		int set_initial_data (const sp_idata_t &input_data, const sp_mesh_iface_t &mesh);

		/**
		* \brief  inits temperature array
		* \param  input_data pointer to idata instance
		* \param  mesh pointer to mesh instance
		* \return 0 on success otherwise negative integer value
		* \todo   remove return values, throw exceptions instead
		* */
		int init_temperature (const sp_idata_t &input_data, const sp_mesh_iface_t &mesh);


		int
		new_simple_get_cell_solution (const double mult, int istart_linear_search,
			const sp_mesh_iface_t &msh, const sp_jacobian_matrix_t &jacobian);

		void set_boundary_builder(sp_boundary_builder boundary_builder);

		/*!
		* \brief destructor
		*/
		~thermal_calc_model();

		//! blue-sky type declaration
		BLUE_SKY_TYPE_DECL_T(thermal_calc_model);


		thermal_calc_model_data_tmp_holder_t        thermal_prev_niter_data_;               //!< thermal_calc_model data stored on previous newton iteration
		thermal_calc_model_data_tmp_holder_t        thermal_old_data_;                      //!< calc_model data stored on previous step
		item_array_t								temperature;	//!< temperature (n_elements)

		data_array_t                                thermal_data;                           //!< array of thermal_calc_model_data, length == n_elements 
		sp_boundary_builder							boundary_builder_;
	};

	bool thermal_calc_model_register_type (const blue_sky::plugin_descriptor &pd);
}
#endif //THERMAL_CALC_MODEL_H